package main

import (
	"context"
	"flag"

	"github.com/gin-gonic/gin"
	"github.com/gogo/protobuf/proto"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
	"github.com/tendermint/tendermint/rpc/client/http"
)

var (
	cli *http.HTTP
)

func searchByHeight(heightList []int64, objectId string) []tmproto.Tx {
	var txs []tmproto.Tx

	for i := len(heightList) - 1; i >= 0; i-- {
		if i+1 < len(heightList) && heightList[i] == heightList[i+1] {
			continue
		}

		h := heightList[i]
		blockRes, err := cli.Block(context.TODO(), &h)
		if err != nil {
			panic(err)
		}

		for index := len(blockRes.Block.Txs) - 1; index >= 0; index-- {
			var tx tmproto.Tx
			if err = proto.Unmarshal(blockRes.Block.Txs[index], &tx); err != nil {
				panic(err)
			}

			var data tmproto.FileData
			if err = proto.Unmarshal(tx.Data, &data); err != nil {
				panic(err)
			}

			if data.ObjectId == objectId {
				// fmt.Println("objectId =", objectId, "height =", h, "index =", index)
				txs = append(txs, tx)
			}
		}
	}

	return txs
}

func NewRouter() *gin.Engine {
	e := gin.Default()
	e.POST("/prov", func(ctx *gin.Context) {
		targetObjectId := ctx.PostForm("object_id")

		var (
			heightList []int64
		)

		abciQueryRes, err := cli.ABCIQuery(context.TODO(), "", nil)
		if err != nil {
			panic(err)
		}

		blockRes, err := cli.Block(context.TODO(), &abciQueryRes.Response.Height)
		if err != nil {
			panic(err)
		}

		mptQueryRes, err := cli.MPTQuery(context.TODO(), blockRes.Block.Header.MPTHash, targetObjectId)
		if err != nil {
			panic(err)
		}

		if mptQueryRes != nil {
			heightList = mptQueryRes.HeightList
		}

		txs := searchByHeight(heightList, targetObjectId)

		ctx.JSON(200, gin.H{
			"code": 0,
			"data": txs,
		})
	})
	return e
}

func main() {
	var (
		addr string
		port string
		err  error
	)

	flag.StringVar(&addr, "addr", ":9090", "the listening address of web service")
	flag.StringVar(&port, "port", "26657", "the port of tendermint rpc service")
	flag.Parse()

	cli, err = http.New("http://localhost:"+port, "/websocket")
	if err != nil {
		panic(err)
	}

	e := NewRouter()
	if err = e.Run(addr); err != nil {
		panic(err)
	}
}
